package com.atguigu.tingshu.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import com.atguigu.tingshu.album.client.AlbumFeignClient;
import com.atguigu.tingshu.common.execption.BusinessException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.utils.ThrowUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategory3;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AlbumSuggestIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumInfoIndexRepository;
import com.atguigu.tingshu.search.repository.AlbumSuggestRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumDetailInfoVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumChannelVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({ "all" })
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumInfoIndexRepository albumInfoIndexRepository;

    @Autowired
    private AlbumSuggestRepository albumSuggestRepository;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * @param @param albumId
     * @return
     * @name upperAlbum
     * @description 将指定专辑上架到索引库
     */
    @Override
    public void upperAlbum(Long albumId) {
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        // 使用CompletableFuture并行执行远程调用
        CompletableFuture<AlbumInfo> albumInfoFuture = CompletableFuture
                .supplyAsync(() -> albumFeignClient.getAlbumInfo(albumId).getData());

        CompletableFuture<AlbumStatVo> albumStatFuture = CompletableFuture
                .supplyAsync(() -> albumFeignClient.getAlbumStatVo(albumId).getData());
        // 等待专辑信息获取完成
        AlbumInfo albumInfo = albumInfoFuture.join();
        ThrowUtil.throwIf(albumInfo == null, ResultCodeEnum.DATA_ERROR, "专辑不存在");
        // 获取分类视图信息（依赖专辑信息）
        CompletableFuture<BaseCategoryView> categoryViewFuture = CompletableFuture
                .supplyAsync(() -> albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData());
        // 复制专辑基本信息
        BeanUtil.copyProperties(albumInfo, albumInfoIndex);
        // 设置专辑属性值
        albumInfoIndex.setAttributeValueIndexList(
                albumInfo.getAlbumAttributeValueVoList().stream().map(albumAttributeValueVo -> {
                    AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                    attributeValueIndex.setAttributeId(albumAttributeValueVo.getAttributeId());
                    attributeValueIndex.setValueId(albumAttributeValueVo.getValueId());
                    return attributeValueIndex;
                }).toList());
        // 等待分类视图信息获取完成
        BaseCategoryView categoryView = categoryViewFuture.join();
        albumInfoIndex.setCategory1Id(categoryView.getCategory1Id());
        albumInfoIndex.setCategory2Id(categoryView.getCategory2Id());
        // 等待统计数据获取完成
        AlbumStatVo albumStatVo = albumStatFuture.join();
        if (albumStatVo != null) {
            albumInfoIndex.setPlayStatNum(albumStatVo.getPlayStatNum());
            albumInfoIndex.setSubscribeStatNum(albumStatVo.getSubscribeStatNum());
            albumInfoIndex.setBuyStatNum(albumStatVo.getBuyStatNum());
            albumInfoIndex.setCommentStatNum(albumStatVo.getCommentStatNum());
        }
        // 计算热度分数：播放量 * 0.2 + 订阅量 * 0.3 + 购买量 * 0.4 + 评论数 * 0.1
        double hotScore = (albumInfoIndex.getPlayStatNum() * 0.2) +
                (albumInfoIndex.getSubscribeStatNum() * 0.3) +
                (albumInfoIndex.getBuyStatNum() * 0.4) +
                (albumInfoIndex.getCommentStatNum() * 0.1);
        albumInfoIndex.setHotScore(hotScore);
        // 保存到ES
        albumInfoIndexRepository.save(albumInfoIndex);

        // 同步保存到自动补全索引
        AlbumSuggestIndex suggestIndex = new AlbumSuggestIndex(albumId, albumInfo.getAlbumTitle());
        albumSuggestRepository.save(suggestIndex);
        log.info("专辑上架成功，已同步到补全索引 - albumId: {}, title: {}", albumId, albumInfo.getAlbumTitle());
    }

    /**
     * @param @param albumId
     * @return
     * @name lowerAlbum
     * @description 将指定专辑从索引库下架
     */
    @Override
    public void lowerAlbum(Long albumId) {
        // 从ES中删除指定专辑
        albumInfoIndexRepository.deleteById(albumId);

        // 同步从自动补全索引中删除
        albumSuggestRepository.deleteById(albumId);
        log.info("专辑下架成功，已从补全索引中删除 - albumId: {}", albumId);
    }

    /**
     * @param @param albumIndexQuery
     * @return @return {@code AlbumSearchResponseVo }
     * @name searchAlbumInfo
     * @description 专辑信息检索
     */
    @Override
    public AlbumSearchResponseVo searchAlbumInfo(AlbumIndexQuery albumIndexQuery) {
        AlbumSearchResponseVo responseVo = new AlbumSearchResponseVo();
        try {
            // 1. 构建查询条件
            SearchRequest searchRequest = this.buildSearchRequest(albumIndexQuery);
            // 2. 查询
            SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest,
                    AlbumInfoIndex.class);
            // 3. 封装数据并返回
            this.buildSearchResponse(responseVo, searchResponse);
            // 4. 设置分页信息
            responseVo.setPageNo(albumIndexQuery.getPageNo());
            responseVo.setPageSize(albumIndexQuery.getPageSize());
            // 5. 计算总页数
            long total = responseVo.getTotal();
            long totalPages = (total + albumIndexQuery.getPageSize() - 1) / albumIndexQuery.getPageSize();
            responseVo.setTotalPages(totalPages);
        } catch (Exception e) {
            log.error("专辑信息检索异常：{}", e.getMessage(), e);
            throw new BusinessException(ResultCodeEnum.SERVICE_ERROR, "专辑信息检索异常");
        }
        return responseVo;
    }

    /**
     * 查询热门专辑（按热度排序）
     *
     * @param category1Id 一级分类ID
     * @param pageNo      页码
     * @return List<AlbumChannelVo>
     */
    @Override
    public List<AlbumChannelVo> findHotAlbum(Long category1Id, Integer pageNo) {
        List<AlbumChannelVo> result = new ArrayList<>();
        try {
            // 1. 获取一级分类下的所有三级分类
            List<BaseCategory3> category3List = albumFeignClient.findTopBaseCategory3(category1Id).getData();
            if (category3List == null || category3List.isEmpty()) {
                log.warn("一级分类{}[]下未找到三级分类", category1Id);
                return result;
            }

            // 2. 对每个三级分类查询前10个热门专辑
            for (BaseCategory3 category3 : category3List) {
                AlbumChannelVo channelVo = new AlbumChannelVo();
                channelVo.setBaseCategory3(category3);

                // 构建查询请求
                SearchRequest searchRequest = SearchRequest.of(s -> s
                        .index("albuminfo")
                        .query(q -> q.bool(b -> b
                                .filter(f -> f.term(t -> t
                                        .field("category3Id")
                                        .value(category3.getId())))))
                        // 按hotScore降序排序
                        .sort(sort -> sort.field(field -> field
                                .field("hotScore")
                                .order(SortOrder.Desc)))
                        // 每个分类取10个
                        .from(0)
                        .size(10));

                // 执行查询
                SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest,
                        AlbumInfoIndex.class);

                // 封装专辑列表
                List<AlbumInfoIndexVo> albumList = new ArrayList<>();
                HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();
                if (hits.hits() != null && !hits.hits().isEmpty()) {
                    albumList = hits.hits().stream().map(hit -> {
                        AlbumInfoIndex source = hit.source();
                        if (source == null) {
                            return null;
                        }
                        AlbumInfoIndexVo albumVo = new AlbumInfoIndexVo();
                        BeanUtil.copyProperties(source, albumVo);
                        return albumVo;
                    }).filter(v -> v != null).collect(Collectors.toList());
                }

                channelVo.setList(albumList);
                result.add(channelVo);
            }

            log.info("热门专辑查询成功 - category1Id: {}, 分类数: {}", category1Id, result.size());
        } catch (Exception e) {
            log.error("热门专辑查询异常：{}", e.getMessage(), e);
            throw new BusinessException(ResultCodeEnum.SERVICE_ERROR, "热门专辑查询异常");
        }
        return result;
    }

    /**
     * 构建ES查询请求
     *
     * @param albumIndexQuery 查询参数
     * @return SearchRequest
     */
    private SearchRequest buildSearchRequest(AlbumIndexQuery albumIndexQuery) {
        return SearchRequest.of(s -> s
                .index("albuminfo")
                .query(q -> q.bool(b -> buildBoolQuery(b, albumIndexQuery)))
                // 4. 排序
                .sort(this.buildSort(albumIndexQuery))
                // 5. 分页
                .from((albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize())
                .size(albumIndexQuery.getPageSize())
                // 6. 高亮设置（标题字段高亮）
                .highlight(h -> h
                        .fields("albumTitle", hf -> hf
                                .preTags("<font color='red'>")
                                .postTags("</font>"))));
    }

    /**
     * 构建Bool查询条件
     *
     * @param boolBuilder     bool查询构建器
     * @param albumIndexQuery 查询参数
     * @return BoolQuery.Builder
     */
    private BoolQuery.Builder buildBoolQuery(BoolQuery.Builder boolBuilder, AlbumIndexQuery albumIndexQuery) {
        // 1. 关键字搜索（多字段匹配：标题、简介、主播名称）
        if (StrUtil.isNotBlank(albumIndexQuery.getKeyword())) {
            boolBuilder.must(m -> m.multiMatch(mm -> mm
                    .fields("albumTitle", "albumIntro", "announcerName")
                    .query(albumIndexQuery.getKeyword())));
        }
        // 2. 分类过滤
        if (albumIndexQuery.getCategory1Id() != null) {
            boolBuilder.filter(f -> f.term(t -> t
                    .field("category1Id")
                    .value(albumIndexQuery.getCategory1Id())));
        }
        if (albumIndexQuery.getCategory2Id() != null) {
            boolBuilder.filter(f -> f.term(t -> t
                    .field("category2Id")
                    .value(albumIndexQuery.getCategory2Id())));
        }
        if (albumIndexQuery.getCategory3Id() != null) {
            boolBuilder.filter(f -> f.term(t -> t
                    .field("category3Id")
                    .value(albumIndexQuery.getCategory3Id())));
        }
        // 3. 属性过滤（嵌套查询）
        if (albumIndexQuery.getAttributeList() != null && !albumIndexQuery.getAttributeList().isEmpty()) {
            for (String attribute : albumIndexQuery.getAttributeList()) {
                // 格式：attributeId:valueId
                String[] split = attribute.split(":");
                if (split.length == 2) {
                    Long attributeId = Long.parseLong(split[0]);
                    Long valueId = Long.parseLong(split[1]);
                    boolBuilder.filter(f -> f.nested(n -> n
                            .path("attributeValueIndexList")
                            .query(nq -> nq.bool(nb -> nb
                                    .must(nm -> nm.term(t -> t
                                            .field("attributeValueIndexList.attributeId")
                                            .value(attributeId)))
                                    .must(nm -> nm.term(t -> t
                                            .field("attributeValueIndexList.valueId")
                                            .value(valueId)))))));
                }
            }
        }
        return boolBuilder;
    }

    /**
     * 构建排序条件
     *
     * @param albumIndexQuery 查询参数
     * @return 排序构建器
     */
    private List<SortOptions> buildSort(AlbumIndexQuery albumIndexQuery) {
        List<SortOptions> sortOptions = new ArrayList<>();

        String order = albumIndexQuery.getOrder();
        if (StrUtil.isNotBlank(order)) {
            String[] split = order.split(":");
            if (split.length == 2) {
                String sortField = split[0];
                String sortOrder = split[1];

                // 确定排序字段
                String field;
                switch (sortField) {
                    case "1" -> field = "hotScore"; // 综合排序（热度分数）
                    case "2" -> field = "playStatNum"; // 播放量
                    case "3" -> field = "createTime"; // 发布时间
                    default -> field = "hotScore";
                }
                // 确定排序方向
                SortOrder sortOrderEnum = "asc".equalsIgnoreCase(sortOrder) ? SortOrder.Asc : SortOrder.Desc;

                sortOptions.add(co.elastic.clients.elasticsearch._types.SortOptions.of(s -> s
                        .field(f -> f.field(field).order(sortOrderEnum))));
            }
        } else {
            // 默认按热度分数降序排序
            sortOptions.add(co.elastic.clients.elasticsearch._types.SortOptions.of(s -> s
                    .field(f -> f.field("hotScore").order(SortOrder.Desc))));
        }

        return sortOptions;
    }

    /**
     * 封装ES查询响应数据
     *
     * @param responseVo     响应VO
     * @param searchResponse ES查询响应
     */
    private void buildSearchResponse(AlbumSearchResponseVo responseVo, SearchResponse<AlbumInfoIndex> searchResponse) {
        HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();

        // 1. 设置总记录数
        long total = hits.total() != null ? hits.total().value() : 0;
        responseVo.setTotal(total);

        // 2. 封装专辑列表数据
        List<AlbumInfoIndexVo> albumList = new ArrayList<>();
        if (hits.hits() != null && !hits.hits().isEmpty()) {
            albumList = hits.hits().stream().map(hit -> {
                AlbumInfoIndex source = hit.source();
                if (source == null) {
                    return null;
                }
                AlbumInfoIndexVo albumVo = new AlbumInfoIndexVo();
                BeanUtil.copyProperties(source, albumVo);
                // 处理高亮标题
                if (hit.highlight() != null && hit.highlight().get("albumTitle") != null) {
                    List<String> highlightList = hit.highlight().get("albumTitle");
                    if (!highlightList.isEmpty()) {
                        albumVo.setAlbumTitle(highlightList.get(0));
                    }
                }
                return albumVo;
            }).filter(v -> v != null).collect(Collectors.toList());
        }
        responseVo.setList(albumList);
    }

    /**
     * 专辑标题自动补全（使用专门的补全索引）
     *
     * @param keyword 关键词
     * @return 匹配的专辑标题列表
     */
    @Override
    public List<String> completeSuggest(String keyword) {
        List<String> result = new ArrayList<>();
        try {
            // 构建 Suggest 查询请求，使用专门的补全索引
            SearchRequest searchRequest = SearchRequest.of(s -> s
                    .index("album_suggest") // 使用新建的补全索引
                    .suggest(suggest -> suggest
                            .suggesters("album-suggest", suggester -> suggester
                                    .prefix(keyword) // 前缀匹配
                                    .completion(completion -> completion
                                            .field("suggest") // 使用completion类型的suggest字段
                                            .size(10) // 返回最多10个建议
                                            .skipDuplicates(true) // 跳过重复项
                                    )))
                    .size(0) // 不需要查询结果，只需要suggest结果
            );

            // 执行查询
            SearchResponse<AlbumSuggestIndex> searchResponse = elasticsearchClient.search(searchRequest,
                    AlbumSuggestIndex.class);

            // 提取 suggest 结果
            if (searchResponse.suggest() != null && searchResponse.suggest().get("album-suggest") != null) {
                result = searchResponse.suggest().get("album-suggest").stream()
                        .flatMap(suggestion -> suggestion.completion().options().stream())
                        .map(option -> option.text())
                        .filter(StrUtil::isNotBlank)
                        .distinct()
                        .collect(Collectors.toList());
            }

            log.info("专辑标题自动补全成功 - keyword: {}, 返回数量: {}", keyword, result.size());
        } catch (Exception e) {
            log.error("专辑标题自动补全异常：{}", e.getMessage(), e);
            throw new BusinessException(ResultCodeEnum.SERVICE_ERROR, "专辑标题自动补全异常");
        }
        return result;
    }

    /**
     * 获取专辑详情
     *
     * @param albumId 专辑ID
     * @return 专辑详情信息
     */
    @Override
    public AlbumDetailInfoVo searchAlbumInfoDetail(Long albumId) {
        AlbumDetailInfoVo detailInfoVo = new AlbumDetailInfoVo();
        try {
            // 使用 CompletableFuture 并行调用多个 Feign 接口，提高性能
            CompletableFuture<AlbumInfo> albumInfoFuture = CompletableFuture
                    .supplyAsync(() -> albumFeignClient.getAlbumInfo(albumId).getData());

            CompletableFuture<AlbumStatVo> albumStatFuture = CompletableFuture
                    .supplyAsync(() -> albumFeignClient.getAlbumStatVo(albumId).getData());

            // 等待专辑信息获取完成
            AlbumInfo albumInfo = albumInfoFuture.join();
            ThrowUtil.throwIf(albumInfo == null, ResultCodeEnum.DATA_ERROR, "专辑不存在");

            // 获取分类视图信息和用户信息（依赖专辑信息中的 category3Id 和 userId）
            CompletableFuture<BaseCategoryView> categoryViewFuture = CompletableFuture
                    .supplyAsync(() -> albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData());

            CompletableFuture<UserInfoVo> userInfoFuture = CompletableFuture
                    .supplyAsync(() -> userFeignClient.getUserInfoVo(albumInfo.getUserId()).getData());

            // 转换 AlbumInfo 为 AlbumInfoVo
            AlbumInfoVo albumInfoVo = new AlbumInfoVo();
            BeanUtil.copyProperties(albumInfo, albumInfoVo);

            // 获取用户信息并脱敏处理（只保留id、名称和头像，保护主播隐私）
            UserInfoVo userInfoVo = userInfoFuture.join();
            if (userInfoVo != null) {
                UserInfoVo safeUserInfo = new UserInfoVo();
                safeUserInfo.setId(userInfoVo.getId());
                safeUserInfo.setNickname(userInfoVo.getNickname());
                safeUserInfo.setAvatarUrl(userInfoVo.getAvatarUrl());
                // 其他敏感信息不设置，保持为null
                detailInfoVo.setAnnouncer(safeUserInfo);
            }
            // 等待所有异步任务完成并封装结果
            detailInfoVo.setAlbumInfo(albumInfoVo);
            detailInfoVo.setAlbumStatVo(albumStatFuture.join());
            detailInfoVo.setBaseCategoryView(categoryViewFuture.join());
            log.info("获取专辑详情成功 - albumId: {}, title: {}", albumId, albumInfo.getAlbumTitle());
        } catch (Exception e) {
            log.error("获取专辑详情异常 - albumId: {}, error: {}", albumId, e.getMessage(), e);
            throw new BusinessException(ResultCodeEnum.SERVICE_ERROR, "获取专辑详情失败");
        }
        return detailInfoVo;
    }

    /**
     * 查询专辑排行榜
     *
     * @param category1Id 一级分类ID
     * @param dimension   排行维度
     * @return List<AlbumInfoIndexVo>
     */
    @Override
    public List<AlbumInfoIndexVo> findRankingList(Long category1Id, String dimension) {
        // 校验维度参数
        ThrowUtil.throwIf(!isValidDimension(dimension), ResultCodeEnum.ILLEGAL_REQUEST, "不支持的排行维度");
        // 1. 先从 Redis 中获取排行榜数据
        String redisKey = "album:ranking:" + category1Id + ":" + dimension;
        List<AlbumInfoIndexVo> rankingList = (List<AlbumInfoIndexVo>) redisTemplate.opsForValue().get(redisKey);
        if (rankingList != null && !rankingList.isEmpty()) {
            log.info("从 Redis 获取排行榜数据 - category1Id: {}, dimension: {}, size: {}",
                    category1Id, dimension, rankingList.size());
            return rankingList;
        }
        // 2. Redis 中没有数据，从 ES 查询（兜底策略）
        log.warn("Redis 中没有排行榜数据，从 ES 查询 - category1Id: {}, dimension: {}", category1Id, dimension);
        rankingList = queryRankingFromES(category1Id, dimension);
        // 3. 将查询结果存入 Redis（设置 2 小时过期，避免定时任务失败时数据完全消失）
        if (rankingList != null && !rankingList.isEmpty()) {
            redisTemplate.opsForValue().set(redisKey, rankingList, 2, TimeUnit.HOURS);
            log.info("排行榜数据已缓存到 Redis - category1Id: {}, dimension: {}", category1Id, dimension);
        }
        return rankingList;
    }

    /**
     * 校验排行维度是否合法
     *
     * @param dimension 排行维度
     * @return boolean
     */
    private boolean isValidDimension(String dimension) {
        return "hotScore".equals(dimension)
                || "playStatNum".equals(dimension)
                || "subscribeStatNum".equals(dimension)
                || "buyStatNum".equals(dimension)
                || "commentStatNum".equals(dimension);
    }

    /**
     * 从 ES 查询排行榜数据
     *
     * @param category1Id 一级分类ID
     * @param dimension   排行维度
     * @return List<AlbumInfoIndexVo>
     */
    private List<AlbumInfoIndexVo> queryRankingFromES(Long category1Id, String dimension) {
        List<AlbumInfoIndexVo> result = new ArrayList<>();
        try {
            // 构建查询请求
            SearchRequest searchRequest = SearchRequest.of(s -> s
                    .index("albuminfo")
                    .query(q -> q.bool(b -> b
                            .filter(f -> f.term(t -> t
                                    .field("category1Id")
                                    .value(category1Id)))))
                    // 按指定维度降序排序
                    .sort(sort -> sort.field(field -> field
                            .field(dimension)
                            .order(SortOrder.Desc)))
                    // 返回 Top 20
                    .size(20));

            // 执行查询
            SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest,
                    AlbumInfoIndex.class);
            HitsMetadata<AlbumInfoIndex> hits = searchResponse.hits();

            if (hits.hits() != null && !hits.hits().isEmpty()) {
                result = hits.hits().stream()
                        .map(hit -> {
                            AlbumInfoIndex albumInfoIndex = hit.source();
                            AlbumInfoIndexVo vo = new AlbumInfoIndexVo();
                            BeanUtil.copyProperties(albumInfoIndex, vo);
                            return vo;
                        })
                        .collect(Collectors.toList());
                log.info("从 ES 查询排行榜成功 - category1Id: {}, dimension: {}, size: {}",
                        category1Id, dimension, result.size());
            }
        } catch (Exception e) {
            log.error("从 ES 查询排行榜异常 - category1Id: {}, dimension: {}, error: {}",
                    category1Id, dimension, e.getMessage(), e);
            throw new BusinessException(ResultCodeEnum.SERVICE_ERROR, "查询排行榜失败");
        }
        return result;
    }

    // TODO 定时任务：每小时更新排行榜数据到 Redis
    // TODO 定时任务方法：updateAlbumRankingToRedis()
    // TODO
    // 需要遍历所有一级分类，对每个分类和每个维度（hotScore、playStatNum、subscribeStatNum、buyStatNum、commentStatNum）
    // TODO 从 ES 查询 Top 100 并存入 Redis，设置过期时间 2 小时
}
